package com.zy.ems.common.async;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 异步处理，默认使用一个定长线程池。
 * 
 * @author Luffy
 *
 */
public class Async {
	private static final Logger logger = LoggerFactory.getLogger(Async.class);

	/**
	 * 大小为10的固定线程池
	 */
	private ExecutorService executorService = Executors.newFixedThreadPool(10);

	Async() {
		super();
	}

	public static Async newInstance() {
		return new Async();
	}

	/**
	 * 使用指定的线程池。
	 * 
	 * @param executorService
	 * @return
	 */
	public Async use(final ExecutorService executorService) {
		if (executorService != null) {
			this.executorService = executorService;
		}
		return this;
	}

	/**
	 * 执行任务异步处理。
	 * 
	 * @param T
	 *            the result type
	 * @param task
	 *            the task
	 * @return
	 */
	public <T> Future<T> execute(final Task<T> task, final FutureCallback<T> callback) {
		final BaseFuture<T> future = new BaseFuture<T>(callback);
		final ExecRunnable<T> runnable = new ExecRunnable<T>(future, task);
		executorService.execute(runnable);

		return future;
	}

	/**
	 * 执行任务异步处理。
	 * 
	 * @param T
	 *            the result type
	 * @param task
	 *            the task
	 * @return
	 */
	public <T> T execute(final Task<T> task) {
		Future<T> future = this.execute(task, null);
		try {
			return future.get();
		} catch (InterruptedException e) {
			logger.error(e.getMessage(), e);
			return null;
		} catch (ExecutionException e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}

	static class ExecRunnable<T> implements Runnable {
		private final BaseFuture<T> future;

		private final Task<T> task;

		ExecRunnable(final BaseFuture<T> future, final Task<T> task) {
			super();
			this.future = future;
			this.task = task;
		}

		public void run() {
			try {
				final T result = this.task.execute();
				this.future.completed(result);
			} catch (final Exception ex) {
				this.future.failed(ex);
			}
		}

	}

}
